﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace SuperKit
{
    class DirCollector : CommandExecutor {
        public bool IsNonParent { get; }
        public bool IsNonFile { get; }
        // 当这个项目为TRUE的时候，所有名称都使用序号简称代替.
        public bool IsShortCut { get; }
        // 当个这项目为TRUE的时候，会把文件名改成序号。
        public bool IsRename { get; }

        public DirCollector(ArgReader arg, IExecutorOwner form, string fpath) : base(arg, form, fpath) {
            IsNonParent = arg.IsContain("-nonParent");
            IsNonFile = arg.IsContain("-nonFile");
            IsShortCut = arg.IsContain("-shortCut");
            IsRename = arg.IsContain("-rename");
        }

        public override void Execute() {
            base.Execute();
            DirectoryInfo info = new DirectoryInfo(FilePath);
            var dirs = info.GetDirectories();
            if (!Kit.IsEmpty(dirs)) {
                MoveDirs(dirs);
                ClearDirs(dirs);
            }
            End();
        }

        private void ClearDirs(DirectoryInfo[] dirs) {
            foreach (var i in dirs) {
                var files = i.GetFiles();
                var subs = i.GetDirectories();
                var count = (files == null ? 0 : files.Length) + (subs == null ? 0 : subs.Length);
                if (count == 0) {
                    i.Delete();
                }
            }
        }

        private void MoveDirs(DirectoryInfo[] dirs) {
            shortCutCount = 0;
            foreach (var i in dirs) {
                ProcessDir(i);
                shortCutCount++;
            }
        }

        private void ProcessFile(FileInfo f) {
            var newName = GetNewName(f);
            MoveFile(f.FullName, newName);
        }

        private int shortCutCount = 0;
        private string GetNewName(FileInfo f) {
            string name = f.Name;
            if (IsRename) {
                var ext = Path.GetExtension(name);
                name = string.Format("{0:D4}{1}", renameIndex++, ext);
            }

            if (IsNonParent) {
                return Path.Combine(FilePath, String.Format("{0}", name));
            } else {
                if (IsShortCut) {
                    string cutName = f.Directory.Name.Substring(0, 1);
                    return Path.Combine(FilePath, String.Format("{0}{1}_{2}", cutName, shortCutCount, name));
                } else {
                    return Path.Combine(FilePath, String.Format("{0}_{1}", f.Directory.Name, name));
                }
                
            }            
        }

        private void ProcessDir(DirectoryInfo dir) {
            var dirs = dir.GetDirectories();
            if (!Kit.IsEmpty(dirs)) {
                foreach (var i in dirs) {
                    MoveDir(dir, i);
                }
            }

            if (IsNonFile == false) {
                var files = dir.GetFiles();
                if (!Kit.IsEmpty(files)) {
                    MoveFiles(files);
                }
            }            
        }

        private int renameIndex;
        private void MoveFiles(FileInfo[] files) {
            renameIndex = 1;
            foreach (var i in files) {
                ProcessFile(i);
            }
        }

        private void MoveDir(DirectoryInfo parent, DirectoryInfo dir) {
            var newName = GetNewDir(parent, dir); //Path.Combine(parent.Parent.FullName, String.Format("{0}_{1}", parent.Name, dir.Name));
            if (Directory.Exists(newName)) {
                newName = GetNonexistDir(newName);                
            }
            //Flush("Move From:{0}", dir.FullName);
            //Flush("Move To  :{0}", newName);

            try {
                Directory.Move(dir.FullName, newName);
            } catch (Exception e) {
                Flush(e.Message);
            }
            
        }

        private static string GetNonexistDir(string newName) {
            var info = new DirectoryInfo(newName);
            var parent = info.Parent;
            var name = info.Name;
            for (int i = 0; i < 100; i++) {
                var path = Path.Combine(parent.FullName, $"{name}_{i + 1}");
                if (Directory.Exists(path) == false) {
                    return path;
                }
            }
            return newName;
        }

        private string GetNewDir(DirectoryInfo parent, DirectoryInfo dir) {
            if (IsNonParent) {
                return Path.Combine(parent.Parent.FullName, String.Format("{0}", dir.Name));
            } else {
                return Path.Combine(parent.Parent.FullName, String.Format("{0}_{1}", parent.Name, dir.Name));
            }
        }
    }
}
